home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 5
/
Skunkware 5.iso
/
src
/
X11
/
xearth-0.92
/
scan.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-06-25
|
11KB
|
517 lines
/*
* scan.c
* kirk johnson
* august 1993
*
* RCS $Id: scan.c,v 1.6 1994/05/23 23:03:26 tuna Exp $
*
* Copyright (C) 1989, 1990, 1993, 1994 Kirk Lauritz Johnson
*
* Parts of the source code (as marked) are:
* Copyright (C) 1989, 1990, 1991 by Jim Frost
* Copyright (C) 1992 by Jamie Zawinski <jwz@lucid.com>
*
* Permission to use, copy, modify, distribute, and sell this
* software and its documentation for any purpose is hereby granted
* without fee, provided that the above copyright notice appear in
* all copies and that both that copyright notice and this
* permission notice appear in supporting documentation. The author
* makes no representations about the suitability of this software
* for any purpose. It is provided "as is" without express or
* implied warranty.
*
* THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
* OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xearth.h"
#include "kljcpyrt.h"
#define MAP_DATA_SCALE (30000)
#define XingTypeEntry (0)
#define XingTypeExit (1)
typedef struct
{
int type;
int cidx;
double x, y;
double angle;
} EdgeXing;
void scan_map();
void scan_outline();
void scan_curves();
double *extract_curve();
void scan_along_curve();
void handle_xings();
void scan_arc();
void scan();
void get_scanbits();
double cos_view_lat;
double sin_view_lat;
double cos_view_lon;
double sin_view_lon;
double proj_scale;
double proj_xofs;
double proj_yofs;
double inv_proj_scale;
int first_scan = 1;
ExtArr scanbits;
ExtArr edgexings;
int min_y, max_y;
ExtArr *scanbuf;
static int double_comp(a, b)
void *a;
void *b;
{
double val_a;
double val_b;
int rslt;
val_a = *((double *) a);
val_b = *((double *) b);
if (val_a < val_b)
rslt = -1;
else if (val_a > val_b)
rslt = 1;
else
rslt = 0;
return rslt;
}
static int scanbit_comp(a, b)
void *a;
void *b;
{
return (((ScanBit *) a)->y - ((ScanBit *) b)->y);
}
static int edgexing_comp(a, b)
void *a;
void *b;
{
double angle_a;
double angle_b;
int rslt;
angle_a = ((EdgeXing *) a)->angle;
angle_b = ((EdgeXing *) b)->angle;
if (angle_a < angle_b)
rslt = -1;
else if (angle_a > angle_b)
rslt = 1;
else
rslt = 0;
return rslt;
}
void scan_map()
{
int i;
double inv_mag;
cos_view_lat = cos(view_lat * (M_PI/180));
sin_view_lat = sin(view_lat * (M_PI/180));
cos_view_lon = cos(view_lon * (M_PI/180));
sin_view_lon = sin(view_lon * (M_PI/180));
inv_mag = 1 / view_mag;
proj_scale = ((hght < wdth)
? (hght / (2 * inv_mag))
: (wdth / (2 * inv_mag)));
proj_xofs = (double) wdth / 2 + shift_x;
proj_yofs = (double) hght / 2 + shift_y;
inv_proj_scale = 1 / proj_scale;
/* the first time through, allocate scanbits.
* on subsequent passes, simply reset it.
*/
if (first_scan)
scanbits = extarr_alloc(sizeof(ScanBit));
else
scanbits->count = 0;
edgexings = extarr_alloc(sizeof(EdgeXing));
scanbuf = (ExtArr *) malloc((unsigned) sizeof(ExtArr) * hght);
assert(scanbuf != NULL);
for (i=0; i<hght; i++)
scanbuf[i] = extarr_alloc(sizeof(double));
scan_outline();
scan_curves();
extarr_free(edgexings);
for (i=0; i<hght; i++)
extarr_free(scanbuf[i]);
free(scanbuf);
qsort(scanbits->body, scanbits->count, sizeof(ScanBit), scanbit_comp);
first_scan = 0;
}
void scan_outline()
{
min_y = hght;
max_y = -1;
scan_arc(1.0, 0.0, 0.0, 1.0, 0.0, 2*M_PI);
get_scanbits(64);
}
void scan_curves()
{
int i;
int cidx;
int npts;
int val;
short *raw;
double *pos;
double *prev;
double *curr;
cidx = 0;
raw = map_data;
while (1)
{
npts = raw[0];
if (npts == 0) break;
val = raw[1];
raw += 2;
pos = extract_curve(npts, raw);
prev = pos + (npts-1)*3;
curr = pos;
min_y = hght;
max_y = -1;
for (i=0; i<npts; i++)
{
scan_along_curve(prev, curr, cidx);
prev = curr;
curr += 3;
}
free(pos);
if (edgexings->count > 0)
handle_xings();
if (min_y <= max_y)
get_scanbits(val);
cidx += 1;
raw += 3*npts;
}
}
double *extract_curve(npts, data)
int npts;
short *data;
{
int i;
double tmp1;
double tmp2;
double *pos;
double *rslt;
rslt = (double *) malloc((unsigned) sizeof(double) * 3 * npts);
assert(rslt != NULL);
pos = rslt;
for (i=0; i<npts; i++)
{
pos[0] = data[0] * (1.0/MAP_DATA_SCALE);
pos[1] = data[1] * (1.0/MAP_DATA_SCALE);
pos[2] = data[2] * (1.0/MAP_DATA_SCALE);
tmp1 = (cos_view_lon * pos[0]) - (sin_view_lon * pos[2]);
tmp2 = (sin_view_lon * pos[0]) + (cos_view_lon * pos[2]);
pos[0] = tmp1;
pos[2] = tmp2;
tmp1 = (cos_view_lat * pos[1]) - (sin_view_lat * pos[2]);
tmp2 = (sin_view_lat * pos[1]) + (cos_view_lat * pos[2]);
pos[1] = tmp1;
pos[2] = tmp2;
data += 3;
pos += 3;
}
return rslt;
}
void scan_along_curve(prev, curr, cidx)
double *prev;
double *curr;
int cidx;
{
double tmp;
double extra[3];
EdgeXing *xing;
if (prev[2] <= 0) /* prev not visible */
{
if (curr[2] <= 0)
return; /* neither point visible */
tmp = curr[2] / (curr[2] - prev[2]);
extra[0] = curr[0] - tmp * (curr[0] - prev[0]);
extra[1] = curr[1] - tmp * (curr[1] - prev[1]);
extra[2] = 0;
tmp = sqrt(extra[0]*extra[0] + extra[1]*extra[1]);
extra[0] /= tmp;
extra[1] /= tmp;
/* extra[] is an edge crossing (entry point) */
xing = (EdgeXing *) extarr_next(edgexings);
xing->type = XingTypeEntry;
xing->cidx = cidx;
xing->x = extra[0];
xing->y = extra[1];
xing->angle = atan2(extra[1], extra[0]);
prev = extra;
}
else if (curr[2] <= 0) /* curr not visible */
{
tmp = curr[2] / (curr[2] - prev[2]);
extra[0] = curr[0] - tmp * (curr[0] - prev[0]);
extra[1] = curr[1] - tmp * (curr[1] - prev[1]);
extra[2] = 0;
tmp = sqrt(extra[0]*extra[0] + extra[1]*extra[1]);
extra[0] /= tmp;
extra[1] /= tmp;
/* extra[] is an edge crossing (exit point) */
xing = (EdgeXing *) extarr_next(edgexings);
xing->type = XingTypeExit;
xing->cidx = cidx;
xing->x = extra[0];
xing->y = extra[1];
xing->angle = atan2(extra[1], extra[0]);
curr = extra;
}
scan(XPROJECT(prev[0]), YPROJECT(prev[1]),
XPROJECT(curr[0]), YPROJECT(curr[1]));
}
void handle_xings()
{
int i;
unsigned nxings;
EdgeXing *xings;
EdgeXing *from;
EdgeXing *to;
xings = (EdgeXing *) edgexings->body;
nxings = edgexings->count;
assert((nxings % 2) == 0);
qsort(xings, nxings, sizeof(EdgeXing), edgexing_comp);
if (xings[0].type == XingTypeExit)
{
for (i=0; i<nxings; i+=2)
{
from = &(xings[i]);
to = &(xings[i+1]);
if ((from->type != XingTypeExit) ||
(to->type != XingTypeEntry))
{
fprintf(stderr, "%s:%d incorrect edgexing sequence ",
__FILE__, __LINE__);
fprintf(stderr, "(from->cidx %d, to->cidx %d)\n",
from->cidx, to->cidx);
exit(1);
}
scan_arc(from->x, from->y, from->angle, to->x, to->y, to->angle);
}
}
else
{
from = &(xings[nxings-1]);
to = &(xings[0]);
if ((from->type != XingTypeExit) ||
(to->type != XingTypeEntry) ||
(from->angle < to->angle))
{
fprintf(stderr, "%s:%d incorrect edgexing sequence ",
__FILE__, __LINE__);
fprintf(stderr, "(from->cidx %d, to->cidx %d)\n",
from->cidx, to->cidx);
exit(1);
}
scan_arc(from->x, from->y, from->angle, to->x, to->y, to->angle+2*M_PI);
for (i=1; i<(nxings-1); i+=2)
{
from = &(xings[i]);
to = &(xings[i+1]);
if ((from->type != XingTypeExit) ||
(to->type != XingTypeEntry))
{
fprintf(stderr, "%s:%d incorrect edgexing sequence ",
__FILE__, __LINE__);
fprintf(stderr, "(from->cidx %d, to->cidx %d)\n",
from->cidx, to->cidx);
exit(1);
}
scan_arc(from->x, from->y, from->angle, to->x, to->y, to->angle);
}
}
edgexings->count = 0;
}
void scan_arc(x0, y0, a0, x1, y1, a1)
double x0, y0, a0;
double x1, y1, a1;
{
int i;
int lo, hi;
double angle, step;
double prev_x, prev_y;
double curr_x, curr_y;
assert(a0 < a1);
step = M_PI / 50;
lo = ceil(a0 / step);
hi = floor(a1 / step);
prev_x = XPROJECT(x0);
prev_y = YPROJECT(y0);
for (i=lo; i<=hi; i++)
{
angle = i * step;
curr_x = XPROJECT(cos(angle));
curr_y = YPROJECT(sin(angle));
scan(prev_x, prev_y, curr_x, curr_y);
prev_x = curr_x;
prev_y = curr_y;
}
curr_x = XPROJECT(x1);
curr_y = YPROJECT(y1);
scan(prev_x, prev_y, curr_x, curr_y);
}
void scan(x0, y0, x1, y1)
double x0, y0;
double x1, y1;
{
int i;
int lo_y, hi_y;
double x_value;
double x_delta;
if (y0 < y1)
{
lo_y = ceil(y0 - 0.5);
hi_y = floor(y1 - 0.5);
if (hi_y == (y1 - 0.5))
hi_y -= 1;
}
else
{
lo_y = ceil(y1 - 0.5);
hi_y = floor(y0 - 0.5);
if (hi_y == (y0 - 0.5))
hi_y -= 1;
}
if (lo_y < 0) lo_y = 0;
if (hi_y >= hght) hi_y = hght-1;
if (lo_y > hi_y)
return; /* no scan lines crossed */
if (lo_y < min_y) min_y = lo_y;
if (hi_y > max_y) max_y = hi_y;
x_value = x0 - (x0 - x1) * (y0 - (lo_y + 0.5)) / (y0 - y1);
x_delta = (x0 - x1) / (y0 - y1);
for (i=lo_y; i<=hi_y; i++)
{
*((double *) extarr_next(scanbuf[i])) = x_value;
x_value += x_delta;
}
}
void get_scanbits(val)
int val;
{
int i, j;
int lo_x, hi_x;
unsigned nvals;
double *vals;
ScanBit *scanbit;
for (i=min_y; i<=max_y; i++)
{
vals = (double *) scanbuf[i]->body;
nvals = scanbuf[i]->count;
assert((nvals % 2) == 0);
qsort(vals, nvals, sizeof(double), double_comp);
for (j=0; j<nvals; j+=2)
{
lo_x = ceil(vals[j] - 0.5);
hi_x = floor(vals[j+1] - 0.5);
if (lo_x < 0) lo_x = 0;
if (hi_x >= wdth) hi_x = wdth-1;
if (lo_x <= hi_x)
{
scanbit = (ScanBit *) extarr_next(scanbits);
scanbit->y = i;
scanbit->lo_x = lo_x;
scanbit->hi_x = hi_x;
scanbit->val = val;
}
}
scanbuf[i]->count = 0;
}
}